package com.zbkj.admin.config;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageInterceptor;
import com.github.pagehelper.dialect.AbstractHelperDialect;
import com.github.pagehelper.page.PageAutoDialect;
import com.github.pagehelper.util.MetaObjectUtil;
import com.mybatisflex.core.FlexConsts;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import java.util.*;

/**
 * 分页插件兼容配置
 */
@Configuration
public class PageHelperAutoConfiguration {

    @Bean
    @Order(0)
    public PageInterceptor pageInterceptor() {
        PageAutoDialect.registerDialectAlias("mysql", CustomMySqlDialect.class);
        PageInterceptor pageInterceptor = new PageInterceptor();
        return pageInterceptor;
    }

    /**
     * 修正分页参数拿不到
     */
    public static class CustomMySqlDialect extends AbstractHelperDialect {

        @Override
        public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql,
                                           CacheKey pageKey) {

            paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow());
            paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize());

            Object[] sqlArgs = (Object[]) ((Map<?, ?>) paramMap).get(FlexConsts.SQL_ARGS);
            List<ParameterMapping> newParameterMappings = new ArrayList<>(boundSql.getParameterMappings());

            // 处理pageKey
            pageKey.update(page.getStartRow());
            pageKey.update(page.getPageSize());
            // 处理参数配置
            if (Objects.nonNull(boundSql.getParameterMappings())) {

                boolean isFlex = Objects.nonNull(sqlArgs);
                Object[] newArgs = null;

                if (page.getStartRow() == 0) {
                    if (isFlex) {
                        newArgs = Arrays.copyOf(sqlArgs, sqlArgs.length + 1);
                        newArgs[newArgs.length - 1] = page.getPageSize();
                    }
                    newParameterMappings.add(parameterMappingBuilder(ms, PAGEPARAMETER_SECOND, int.class));
                } else {
                    if (isFlex) {
                        newArgs = Arrays.copyOf(sqlArgs, sqlArgs.length + 2);
                        newArgs[newArgs.length - 2] = page.getStartRow();
                        newArgs[newArgs.length - 1] = page.getPageSize();
                    }
                    newParameterMappings.add(parameterMappingBuilder(ms, PAGEPARAMETER_FIRST, long.class));
                    newParameterMappings.add(parameterMappingBuilder(ms, PAGEPARAMETER_SECOND, int.class));
                }

                if (isFlex) {
                    paramMap.put(FlexConsts.SQL_ARGS, newArgs);
                }

                MetaObjectUtil.forObject(boundSql).setValue("parameterMappings", newParameterMappings);

            }
            return paramMap;
        }

        private ParameterMapping parameterMappingBuilder(MappedStatement ms, String key, Class<?> clazz) {
            return new ParameterMapping.Builder(ms.getConfiguration(), key, clazz).build();
        }

        @Override
        public String getPageSql(String sql, Page page, CacheKey pageKey) {
            return sql + (page.getStartRow() == 0 ? "\n LIMIT ? " : "\n LIMIT ?, ? ");
        }

    }

}
